<!-- Created by henian.xu on 2018/8/30. -->

<template>
    <div :class="['form-item',{'feedback':isFeedback},{'success':isSuccess},{'error':isError}]">
        <div class="body">
            <div 
                class="required" 
                :class="hasInner && 'hasWrap'">*</div>
            <Label
                v-bind="__labelProps"
                v-if="hasLabel || hasSubLabel || icon">
                <template slot="icon">
                    <slot name="icon"/>
                </template>
                <template slot="inner">
                    <slot name="inner"/>
                </template>
                <template slot="label">
                    <slot name="label"/>
                </template>
                <template slot="subLabel">
                    <slot name="subLabel"/>
                </template>
                <!--<slot/>-->
            </Label>
            <div class="inner">
                <div class="content"><slot/></div>
                <!-- 反馈 -->
                <div
                    v-if="isSuccess || isError"
                    class="feedback">
                    <i
                        v-if="isFeedback && isSuccess"
                        class="f-icon">&#xf019;</i>
                    <i
                        v-if="!isFeedback && isError"
                        class="f-icon">&#xf041;</i>
                </div>
            </div>
        </div>
        <!-- 描述 -->
        <slot name="desc">
            <div
                v-if="desc"
                class="desc">{{ desc }}</div>
        </slot>
        <!-- 反馈 -->
        <div
            v-if="isFeedback&&(isSuccess||isError)"
            class="feedback">
            <!--<i
                v-if="isSuccess" 
                class="f-icon">&#xf019;</i>-->
            <i 
                v-if="isError" 
                class="f-icon">&#xf041;</i>
            {{ validateMessage }}
        </div>
    </div>
</template>

<script>
import { Comm } from '@/utils';
import AsyncValidator from 'async-validator';
import labelMixin from '@/components/label/labelMixin';
export default {
    name: 'FormItem',
    mixins: [labelMixin],
    inject: ['xForm'],
    data() {
        return {
            validateState: '',
            validateMessage: '',
        };
    },
    props: {
        rules: {
            type: Object,
            default() {
                return null;
            },
        },
        prop: {
            type: String,
            default: '',
        },
        desc: {
            type: String,
            default: '',
        },
        feedback: {
            type: Boolean,
            default: false,
        },
    },
    computed: {
        formRules() {
            return Comm.getObjectValueByPath(this.xForm.rules, this.prop) || [];
        },
        fieldValue: {
            get() {
                const models = this.xForm.models;
                let path = this.prop;
                if (!models || !path) return;
                if (path.indexOf(':') !== -1) {
                    path = path.replace(/:/, '.');
                }
                return Comm.getObjectValueByPath(models, path);
            },
            cache: false,
        },
        mergeRules() {
            return [].concat(this.rules || this.formRules);
        },
        isValidating() {
            return this.validateState === 'validating';
        },
        isSuccess() {
            return this.validateState === 'success';
        },
        isError() {
            return this.validateState === 'error';
        },
        isFeedback() {
            return this.xForm.feedback || this.feedback;
        },
    },
    watch: {
        fieldValue() {
            this.validate('change').catch(() => {
                /*只为了去除控制台多余的输出*/
            });
        },
    },
    methods: {
        filterRules(trigger) {
            return this.mergeRules
                .filter(rule => {
                    return !rule.trigger || rule.trigger.indexOf(trigger) !== -1;
                })
                .map(rule => ({ ...rule }));
        },
        validate(trigger) {
            let callback;
            const promise = new Promise((resolve, reject) => {
                callback = msg => {
                    msg ? reject(msg) : resolve(true);
                };
            });

            this.validateState = 'validating';
            const currRules = this.filterRules(trigger);
            const descriptor = {}; //An object declaring validation rules
            if (!currRules.length) {
                callback();
            } else {
                currRules.forEach(rule => {
                    delete rule.trigger;
                });
                descriptor[this.prop] = currRules;
                const validator = new AsyncValidator(descriptor);
                const model = {
                    [this.prop]: this.fieldValue,
                };
                validator.validate(model, { firstFields: true }, errors => {
                    this.validateState = !errors ? 'success' : 'error';
                    this.validateMessage = errors ? errors[0].message : '';
                    callback(this.validateMessage);
                });
            }
            return promise;
        },
    },
    created() {
        this.xForm.addField(this);
    },
    beforeDestroy() {
        this.xForm.removeField(this);
    },
};
</script>

<style lang="scss">
.form-item {
    padding: $padding;
    + .form-item {
        border-top: 1px solid $color-border;
    }

    > .body {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        align-items: stretch;

        > .required {
            color: $color-danger;
            line-height: 60px;
            &.hasWrap {
                line-height: $line-height;
            }
        }
        > .x-label {
            flex: 0 0 auto;
            align-items: flex-start;
            line-height: 60px;
        }
        > .inner {
            flex: 1 1 1%;
            display: flex;
            flex-direction: row;
            justify-content: space-between;

            > .content {
                flex: 1 1 1%;
                padding: 0 $padding-small;
            }
            > .feedback {
                flex: 0 0 auto;
                line-height: 60px;
                > .f-icon {
                    line-height: 1;
                }
            }
        }
    }
    > .desc {
        color: $gray6;
    }
    &.success {
        .feedback {
            color: $color-success;
        }
    }
    &.error {
        .feedback {
            color: $color-danger;
        }
    }
}
</style>
